using System;
using System.Collections;
using System.Collections.Generic;
using Life.UI.MVC.Controller;
using Life.UI.MVC.Model;
using Life.UI.MVC.Loader;
using UnityEngine;
using UnityEngine.PlayerLoop;
using ControllerTypeValue = System.Int32;

namespace Life.UI.MVC
{
    /// <summary>
    /// UI管理器，使用时请确保在场景中有一个UIManager的实例
    /// </summary>
    public sealed class UIManager : MonoBehaviour,ITokenToString
    {
        private static UIManager _instance;
        
        public static bool Initialized
        {
            get;
            private set;
        }

        public static event System.Action OnInitialized;
        
        private readonly Dictionary<ControllerTypeValue, ControllerBase> _modelDict = new Dictionary<ControllerTypeValue, ControllerBase>();
        private readonly Dictionary<ControllerTypeValue, UIWaiter> _controllerLoadWaiter = new Dictionary<ControllerTypeValue, UIWaiter>();
        private readonly Stack<PageArchiveDataBase> _cacheStack = new Stack<PageArchiveDataBase>();
#if MVCUI_EVENT
        private readonly Dictionary<ControllerTypeValue,System.Action> _viewShowActions = new Dictionary<ControllerTypeValue, System.Action>();
        private readonly Dictionary<ControllerTypeValue, System.Action> _viewHideActions = new Dictionary<ControllerTypeValue, System.Action>();
        private readonly Dictionary<ControllerTypeValue,System.Action> _viewShowActionsOnce = new Dictionary<ControllerTypeValue, System.Action>();
        private readonly Dictionary<ControllerTypeValue, System.Action> _viewHideActionsOnce = new Dictionary<ControllerTypeValue, System.Action>();
#endif 
        
#region 实例变量
        [SerializeField]LayerRoot layerRoot;
        [SerializeField]GameObject uiLoaderPrefab;
        UILoader _uiUILoader;
#endregion
#if UNITY_EDITOR
        [SerializeField] [Header("Only Editor")]private bool autoShowUI = true;
#endif
        
#if !MVCUI_CUSTOM_ENABLED
        [SerializeField][ControllerTypeSelect]ControllerTypeValue[] defaultShowUI;
#else
        private ITokenToString _tokenConvert; 
#endif
        private void Awake()
        {
            if (_instance != null)
            {
                Destroy(gameObject);
            }
        }

        private void Start()
        {
            if(uiLoaderPrefab!=null)
            {
                _uiUILoader = !uiLoaderPrefab.activeInHierarchy ? Instantiate(uiLoaderPrefab).GetComponent<UILoader>() : uiLoaderPrefab.GetComponent<UILoader>(); //检查是否为场景对象
                _uiUILoader.gameObject.SetActive(true);
                _uiUILoader.enabled = true;
            }
            if (_uiUILoader.Initialized)
            {
                Initialize();
            }
            else
            {
                _uiUILoader.OnInitialized += Initialize;
            }
        }
        
        void Initialize()
        {
            _instance = this;
            _instance._tokenConvert = this;
            Initialized = true;
            OnInitialized?.Invoke();
            OnInitialized = null;
            StateModel stateModel = new StateModel(0);
#if !MVCUI_CUSTOM_ENABLED
            if (defaultShowUI != null
#if UNITY_EDITOR
                && autoShowUI
#endif
               )
            {
                foreach (var controllerType in defaultShowUI)
                {
                    stateModel.Token = controllerType;
                    stateModel.Enable = true;
                    stateModel.TransferTag = false;
                    UpdateView(stateModel);
                }
            }
#else
            var defaultUISetter = GetComponent<IDefaultUISetter>();
            if (defaultUISetter != null 
#if UNITY_EDITOR
                && autoShowUI
#endif
                )
            {
                for (int i = 0; i < defaultUISetter.Length; ++i)
                {
                    stateModel.Token = defaultUISetter.Value(i);
                    stateModel.Enable = true;
                    stateModel.TransferTag = false;
                    UpdateView(stateModel);
                }
            }
#endif
        }

        /// <summary>
        /// 添加一个UI控制器
        /// </summary>
        /// <param name="controller"></param>
        /// <returns>返回值为false时，说明当前添加被延迟需要等待UIManager初始化完成</returns>
        public static bool AddController(ControllerBase controller)
        {
            if (Initialized)
            {
                if (!_instance._modelDict.TryAdd(controller.TargetControllerType, controller))
                {
                    Debug.LogError($"Dev: RegisterController Failed, ModelToken: {controller.TargetControllerType} already exist controller.");
                }
                return true;
            }
            else
            {
                OnInitialized += () => AddController(controller);
                return false;
            }
        }
       /// <summary>
       /// 移除一个UI控制器
       /// </summary>
       /// <param name="controller"></param>
        public static void RemoveController(ControllerBase controller)
        {
            if (Initialized)
            {
                _instance._modelDict.Remove(controller.TargetControllerType);
            }
        }
        
        /// <summary>
        /// 检查当前UI是否已经被加载
        /// </summary>
        /// <param name="typeValue"></param>
        /// <returns></returns>
        public static bool CheckController(ControllerTypeValue typeValue)
        {
            if (Initialized)
            {
                return _instance._modelDict.ContainsKey(typeValue);
            }

            return false;
        }

        /// <summary>
        /// 存档一个Page数据
        /// </summary>
        /// <param name="pageArchiveData"></param>
        public static void ArchivePage(PageArchiveDataBase pageArchiveData)
        {
            if (Initialized)
            {
                _instance._cacheStack.Push(pageArchiveData);
            }
        }
        /// <summary>
        /// 检查是否还有Page存档
        /// </summary>
        public static bool HasArchive => _instance._cacheStack.Count > 0;

        /// <summary>
        /// 弹出一个Archive，恢复Page
        /// </summary>
        public static void PopArchive()
        {
            if (Initialized)
            {
                if (_instance._cacheStack.Count > 0)
                {
                    var data = _instance._cacheStack.Pop();
                    UpdateView(new PageArchiveModel(data));
                }
            }
        }
        /// <summary>
        /// 更新UI的视图
        /// </summary>
        /// <param name="model"></param>
        public static void UpdateView(ModelBase model)
        {
            if (Initialized)
            {
                if(_instance._modelDict.TryGetValue(model.Token, out var controller))
                {
#if MVCUI_EVENT
                    bool beforeState = controller.ViewState;
#endif
                    controller.UpdateView(model);
#if MVCUI_EVENT
                    if (beforeState)
                    {
                        if (!controller.ViewState)
                        {
                            if (_instance._viewHideActionsOnce.Remove(controller.TargetControllerType,
                                    out var actionOnce))
                            {
                                actionOnce?.Invoke();
                            }

                            if (_instance._viewHideActions.TryGetValue(controller.TargetControllerType,
                                    out var action))
                            {
                                action?.Invoke();
                            }
                           
                        }
                    }
                    else
                    {
                        if (controller.ViewState)
                        {
                            if (_instance._viewShowActionsOnce.Remove(controller.TargetControllerType,
                                    out var actionOnce))
                            {
                                actionOnce?.Invoke();
                            }

                            if (_instance._viewShowActions.TryGetValue(controller.TargetControllerType,
                                    out var action))
                            {
                                action?.Invoke();
                            }
                        }
                    }
#endif
                }
                else
                {
                    if (_instance.LoadUI(model.Token,out controller))
                    {
                        if (_instance._controllerLoadWaiter.TryGetValue(controller.TargetControllerType, out var controllerWaiter))
                        {
                            controllerWaiter?.SetComplete();
                        }
                        UpdateView(model);
                        //controller.UpdateView(model);
                    }
                }
            }
        }

        /// <summary>
        /// 用于便利地显示UI 仅展示不做其他操作
        /// </summary>
        /// <param name="typeValue"></param>
        public static void ShowView(ControllerTypeValue typeValue)
        {
            UpdateView(new StateModel (typeValue) { Enable = true });
        }

        /// <summary>
        /// 设置Token转Convert
        /// </summary>
        /// <param name="tokenConvert"></param>
        public static void SetTokenConvert(ITokenToString tokenConvert)
        {
            if (Initialized)
            {
                _instance._tokenConvert = tokenConvert ?? _instance;
            }
        }

        /// <summary>
        /// 用于快速移除某个UI
        /// </summary>
        /// <param name="typeValue"></param>
        public static void RemoveView(ControllerTypeValue typeValue)
        {
            if (Initialized)
            {
                if(_instance._modelDict.TryGetValue(typeValue, out var controller))
                {
                    _instance._modelDict.Remove(typeValue);
                    Destroy(controller.gameObject);
                }
            }
        }

        /// <summary>
        /// 获取当前UI的状态 实在显示
        /// </summary>
        /// <param name="typeValue"></param>
        /// <returns></returns>
        public static bool ViewState(ControllerTypeValue typeValue)
        {
            if (Initialized)
            {
                if (_instance._modelDict.TryGetValue(typeValue, out var controller))
                {
                    return controller.ViewState;
                }
            }

            return false;
        }
        
        /// <summary>
        /// 等待UI隐藏 用于协程 调用方法 --> yield return UIManager.WaitViewHide(ControllerTypeValue);
        /// </summary>
        /// <param name="typeValue"></param>
        /// <returns></returns>
        public static IEnumerator WaitViewHide(ControllerTypeValue typeValue)
        {
            if (Initialized)
            {
                if(_instance._modelDict.TryGetValue(typeValue, out var controller))
                {
                    return new WaitUntil(()=>controller.ViewState == false);
                }
            }
            return null;
        }
        
        private static readonly WaitHandler DefWaitHandler = new WaitHandler(null,null);
        /// <summary>
        /// 在UI隐藏后立即执行某个操作，如果当前UI未加载或为隐藏状态则立即执行
        /// </summary>
        /// <param name="typeValue"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public static WaitHandler AfterViewHide(ControllerTypeValue typeValue,System.Action action)
        {
            if (Initialized)
            {
                if(_instance._modelDict.TryGetValue(typeValue, out var controller))
                {
                    if(controller.ViewState == false)
                    {
                        action?.Invoke();
                        return DefWaitHandler;
                    }
                    CoroutineRef coroutineRef = new CoroutineRef();
                    var coroutine = controller.StartCoroutine(AfterViewHide(controller, action,coroutineRef));
                    coroutineRef.RefCoroutine = coroutine;
                    return new WaitHandler(coroutineRef,controller);
                }
                //如果当前UI未加载则直接执行
                action?.Invoke();
                return DefWaitHandler;
            }
            return DefWaitHandler;
        }
        
        private static IEnumerator AfterViewHide(ControllerBase controllerBase,System.Action action,CoroutineRef coroutineRef)
        {
            yield return new WaitUntil(() => controllerBase.ViewState == false);
            coroutineRef.RefCoroutine = null;
            action?.Invoke();
        }


        /// <summary>
        /// 等待UI展示 用于协程 调用方法 --> yield return UIManager.WaitViewHide(ControllerTypeValue);
        /// </summary>
        /// <param name="typeValue"></param>
        /// <returns></returns>
        public static IEnumerator WaitViewShow(ControllerTypeValue typeValue)
        {
            if (Initialized)
            {
                if(_instance._modelDict.TryGetValue(typeValue, out var controller))
                {
                    return new WaitUntil(()=>controller.ViewState);
                }
                if (_instance._controllerLoadWaiter.TryGetValue(typeValue,
                        out var controllerWaiter))
                {
                    return controllerWaiter;
                }
                else
                {
                    UIWaiter waitComplete = new UIWaiter();
                    _instance._controllerLoadWaiter.Add(typeValue, waitComplete);
                    return waitComplete;
                }
            }
            return null;
        }

        /// <summary>
        /// 获取控制器缓存
        /// </summary>
        /// <param name="typeValue"></param>
        /// <returns></returns>
        public static object ViewControllerCache(ControllerTypeValue typeValue)
        {
            if (Initialized)
            {
                if(_instance._modelDict.TryGetValue(typeValue, out var controller))
                {
                    return controller.ControllerCache();
                }
            }
            return null;
        }

        /// <summary>
        /// 用于便利地隐藏 View
        /// </summary>
        /// <param name="typeValue"></param>
        /// <param name="clearView"></param>
        public static void HideView(ControllerTypeValue typeValue,bool clearView = true)
        {
            UpdateView(new StateModel (typeValue) { Enable = false, ClearView = clearView });
        }
        /// <summary>
        /// 启动一个协程
        /// </summary>
        /// <param name="enumerator"></param>
        /// <returns></returns>
        public static Coroutine CoroutineStart(IEnumerator enumerator)
        {
            return Initialized ? _instance.StartCoroutine(enumerator) : null;
        }
        /// <summary>
        /// 关闭一个协程
        /// </summary>
        /// <param name="coroutine"></param>
        public static void CoroutineStop(Coroutine coroutine)
        {
            if (Initialized)
            {
                _instance.StopCoroutine(coroutine);
            }
        }
        /// <summary>
        /// 将当前Token转为字符
        /// </summary>
        /// <param name="typeValue"></param>
        /// <returns></returns>
        public static string ConvertTokenToString(ControllerTypeValue typeValue)
        {
            return Initialized ? _instance._tokenConvert.ToString(typeValue) : typeValue.ToString();
        }
        /// <summary>
        /// 加载对应的 View
        /// </summary>
        /// <param name="token"></param>
        /// <param name="controller"></param>
        /// <returns></returns>
        private bool LoadUI(ControllerTypeValue token,out ControllerBase controller)
        {
            if (_uiUILoader != null)
            {
                var ui = _uiUILoader.Load(token);
                if (ui == null)
                {
                    Debug.LogError($"Dev: LoadUI Failed, ModelToken: {_tokenConvert?.ToString(token)} dose not have a UI.");
                    Debug.LogError($"Dev: UpdateModel Failed, ModelToken: {_tokenConvert?.ToString(token)} not be supported.");
                    controller = null;
                    return false;
                }
                else
                {
                    controller = ui.GetComponent<ControllerBase>();
                    layerRoot.AddController(controller);
                    return true;
                }
            }
            else
            {
                Debug.LogError("Dev: UI Loader is null.");
                controller = null;
                return false;
            }
        }
#if MVCUI_EVENT
        public static void RegisterViewShowEvent(ControllerTypeValue controllerType, System.Action action,bool once = false)
        {
            if (_instance != null)
            {
                if (once)
                {
                    if (!_instance._viewShowActionsOnce.TryGetValue(controllerType, out var actionOut))
                    {
                        actionOut = action;
                        _instance._viewShowActionsOnce[controllerType] = actionOut;
                    }
                    else
                    {
                        actionOut += action;
                    }
                }
                else
                {
                    if (!_instance._viewShowActions.TryGetValue(controllerType, out var actionOut))
                    {
                        actionOut = action;
                        _instance._viewShowActions[controllerType] = actionOut;
                    }
                    else
                    {
                        actionOut += action;
                    }
                }
            }
        }
        
        public static void RemoveViewShowEvent(ControllerTypeValue controllerType, System.Action action,bool once = false)
        {
            if (_instance != null)
            {
                if (once)
                {
                    if (_instance._viewShowActionsOnce.TryGetValue(controllerType, out var actionOut))
                    {
                        actionOut -= action;
                    }
                }
                else
                {
                    if (_instance._viewShowActions.TryGetValue(controllerType, out var actionOut))
                    {
                        actionOut -= action;
                    }
                }
            }
        }
        
        public static void RegisterViewHideEvent(ControllerTypeValue controllerType, System.Action action,bool once = false)
        {
            if (_instance != null)
            {
                if (once)
                {
                    if (!_instance._viewHideActionsOnce.TryGetValue(controllerType, out var actionOut))
                    {
                        actionOut = action;
                        _instance._viewHideActionsOnce[controllerType] = actionOut;
                    }
                    else
                    {
                        actionOut += action;
                    }
                }
                else
                {
                    if (!_instance._viewHideActions.TryGetValue(controllerType, out var actionOut))
                    {
                        actionOut = action;
                        _instance._viewHideActions[controllerType] = actionOut;
                    }
                    else
                    {
                        actionOut += action;
                    }
                }
            }
        }
        
        public static void RemoveViewHideEvent(ControllerTypeValue controllerType, System.Action action,bool once = false)
        {
            if (_instance != null)
            {
                if (once)
                {
                    if (_instance._viewHideActionsOnce.TryGetValue(controllerType, out var actionOut))
                    {
                        actionOut -= action;
                    }
                }
                else
                {
                    if (_instance._viewHideActions.TryGetValue(controllerType, out var actionOut))
                    {
                        actionOut -= action;
                    }
                }
            }
        }
#endif
        
        private void OnDestroy()
        {
            if (_instance == this)
            {
                _modelDict.Clear();

                _controllerLoadWaiter.Clear();
                _cacheStack.Clear();
#if MVCUI_EVENT
                _viewShowActions.Clear();
                _viewHideActions.Clear();
                _viewShowActionsOnce.Clear();
                _viewHideActionsOnce.Clear();
#endif 
                Initialized = false;
                _instance = null;
            }
        }

        string ITokenToString.ToString(int token)
        {
            return token.ToString();
        }
    }

    public class CoroutineRef
    {
        public Coroutine RefCoroutine
        {
            get;
            set;
        }
    }
    public class WaitHandler
    {
        private CoroutineRef _coroutine;
        private readonly ControllerBase _controller;

        public WaitHandler(CoroutineRef coroutine, ControllerBase controller)
        {
            _coroutine = coroutine;
            _controller = controller;
        }

        public bool IsWaiting => _coroutine.RefCoroutine != null;

        public void StopWait()
        {
            if (_coroutine is { RefCoroutine: not null } && _controller != null)
            {
                _controller.StopCoroutine(_coroutine.RefCoroutine);
                _coroutine = null;
            }
        }
    }
    
    public interface ITokenToString
    {
        string ToString(int token);
    }
}
